package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.servlet.http.HttpServletRequest;

/**
 * @author sunjipu
 * @create 2020-04-17 10:55
 */
@Component
public class AuthGlobalFilter implements GlobalFilter {

    @Autowired
    private RedisTemplate redisTemplate;

    // 匹配路径的工具类
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Value("${authUrls.url}")
    private String authUrls;

    //判断请求 是否必须要登录
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();//请求

        ServerHttpResponse response = exchange.getResponse();//响应
        //请求路径  http://www.gmall.com    /list.html
        //请求路径  http://www.gmall.com    /api/product/inner/**  VUE Ajax  response.data.message
        //1:
        String path = request.getURI().getPath();

        System.out.println(path);

        if (antPathMatcher.match("/**/inner/**", path)) {
            //匹配上了 此资源是内部资源 不允许网关路由
            return out(response, ResultCodeEnum.PERMISSION);
        }

        //获取用户ID
        String userId = getUserId(request);
        //2: /api/user/auth/**  auth字样的请求 要求必须登录才能访问  异步Ajax 局部刷新
        if (antPathMatcher.match("/**/auth/**", path)) {
            //匹配上
            //判断用户是否登录   用户ID
            if (StringUtils.isEmpty(userId)) {
                //未登录
                return out(response, ResultCodeEnum.LOGIN_AUTH);
            }

        }

        //3:匹配请求路径 trade.html 订单页面  myOrder.html 支付页面 pay.html    同步刷新页面时
        for (String authUrl : authUrls.split(",")) {
            // 当前的url包含登录的控制器域名，但是用户Id 为空！
            if (path.indexOf(authUrl)!=-1 && StringUtils.isEmpty(userId)){
                //ServerHttpResponse responses = exchange.getResponse();
                //303状态码表示由于请求对应的资源存在着另一个URI，应使用重定向获取请求的资源
                response.setStatusCode(HttpStatus.SEE_OTHER);
                response.getHeaders().set(HttpHeaders.LOCATION,"http://www.gmall.com/login.html?originUrl="+request.getURI());
                // 重定向到登录
                return response.setComplete();
            }

        }
        //设置网关请求头
//判断是否为空
        if(!StringUtils.isEmpty(userId)){
            request.mutate().header("userId",userId);
        }
        String userTempId = getUserTempId(request);
        if(!StringUtils.isEmpty(userTempId)){
            request.mutate().header("userTempId",userTempId);
        }
        return chain.filter(exchange);
    }

    //获取用户ID  令牌 从Redis缓存中获取出用户ID    K：令牌 V：用户ID
    public String getUserId(ServerHttpRequest request){
        //获取令牌  从请求头中  从Cookie
        String token = request.getHeaders().getFirst("token");//""
        if(StringUtils.isEmpty(token)){
            //请求头中没有  从Cookie获取
            HttpCookie httpCookie = request.getCookies().getFirst("token");
            if(httpCookie != null){
                token = httpCookie.getValue();
            }
        }
        if(!StringUtils.isEmpty(token)){
            //此令牌在缓存中是否也存在  存在取出 用户ID
            if(redisTemplate.hasKey("user:login:" + token)){
                //获取用户ID
                return (String) redisTemplate.opsForValue().get("user:login:" + token);
            }
        }
        return null;

    }


    //返回值响应Result实体
    private Mono<Void> out(ServerHttpResponse response,ResultCodeEnum resultCodeEnum) {

        Result<Object> result = Result.build(null, resultCodeEnum);
        byte[] bytes = JSON.toJSONString(result).getBytes();
        DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);
        //响应头
        //响应体  Result转成二进制  中文不乱码
        response.getHeaders().set(HttpHeaders.CONTENT_TYPE,"application/json;charset=utf-8");
        return response.writeWith(Mono.just(dataBuffer));

    }

    private String getUserTempId(ServerHttpRequest request){
        String userTempId = request.getHeaders().getFirst("userTempId");
        if(null != userTempId){
            return userTempId;
        }
        HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
        if(null != httpCookie){
            return  httpCookie.getValue();
        }
        return null;
    }


}